iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
0

前言

在介紹完基本的 Node、Topic、Message 後,再來便是實做 Publisher 與 Subscriber 囉。今天我們會介紹使用 Python 來撰寫 Publisher 的方法,以下進入正題:

使用 Python 撰寫 Publisher

首先進到 beginner_tutorial/src/ ,並建立新檔案 talker.py

roscd beginner_tutorial/src/
touch talker.py

接著,在裡面輸入以下程式碼:

#!/usr/bin/env python
# license removed for brevity
import rospy
from std_msgs.msg import String

def talker():
  pub = rospy.Publisher('chatter', String, queue_size=10)
  rospy.init_node('talker', anonymous=True)
  rate = rospy.Rate(10) # 10hz
  while not rospy.is_shutdown():
    hello_str = "hello world %s" % rospy.get_time()
    rospy.loginfo(hello_str)
    pub.publish(hello_str)
    rate.sleep()
    
if __name__ == '__main__':
  try:
    talker()
  except rospy.ROSInterruptException:
    pass

詳細解析一下程式碼:

#!/usr/bin/env python

這一行程式碼其實在 DAY7 就有簡單提到了。假設我們在檔案中加入此行註釋,那麼在 Terminal 上輸入 ./[file_name] 就可以直接執行檔案!換言之,我們可以使用 ./ 取代在 Terminal上輸入 python [file_name]python

import rospy
from std_msgs.msg import String

這兩行表示我們於檔案中匯入了 rospy 以及 std_msgs.msg 當中的 String。兩者的功用在於,假設我們想利用 Python 寫出 ROS node 相關的指令時,就必須 import rospyfrom std_msgs.msg import String 則和上面提到的 Message 格式有關,表示我們可以使用 String 這個 Message 格式在 Topics 之間交換資料。

def talker():
  pub = rospy.Publisher('chatter', String, queue_size=10)
  rospy.init_node('talker', anonymous=True)
  rate = rospy.Rate(10) # 10hz
  while not rospy.is_shutdown():
    hello_str = "hello world %s" % rospy.get_time()
    rospy.loginfo(hello_str)
    pub.publish(hello_str)
    rate.sleep()

這邊定義了 talker 這個函式的內容,因此會稍微冗長一點:
首先,第2行設定了 Node 與 Topic 之間的關係,原函式定義為 rospy.Publisher(topic_name, msg_type, queue_size),表示該 Node 可針對 [topic_name] 發布格式為 [msg_type] 的 Message,[queue_size] 是設定最多可儲存幾筆 Message,以避免任何 Subscriber 來不及接收 Message。

第3行初始化名稱為 talker 的這個 Node,[anonymous] 則針對需要同時執行多個該 Node 時所設定,由於 ROS當中 Nodes 的名稱不可重複,若有重複名稱的 Node 被執行時,較早執行的 Node 會被關閉。因此初始化 Node 時如果設定 [anonymous=True],執行檔案時系統會自動在 Node 名稱後加上亂數,如此即可輕易創建多個不同名稱但功能相同的 Nodes。

第4行設定了迴圈間隔的頻率,通常會與第9行的 ros.sleep() 同時使用。rospy.Rate(10) 表示每 0.1秒作1次迴圈,也就是說 ros.Rate() 內的參數表示的是頻率,單位為赫茲(Hz),至於 ros.sleep() 這邊以下圖來解釋:假設每作一次迴圈只需要0.07秒,但因為 ros.Rate() 設定為 10,則 ros.sleep() 會使該 Node 等待0.03秒後再執行下個迴圈,以此類推。
https://ithelp.ithome.com.tw/upload/images/20200925/20129808JXGmk9Five.jpg

第5行 rospy.is_shotdown() 也在 DAY7 介紹過了,利用 while not 即可達到程式關閉前會持續進行該迴圈的結果。

第6行是將字串 "hello world" 和時間存進 hello_str 當中,第7行則是將 hello_str 的內容印到螢幕並寫入 ROS log 裡。

第8行 pub.publish(hello_str),便是使用第2行提到的功能,將 hello_str 這個 Message 發佈至 Topic 上。

if __name__ == '__main__':
  try:
    talker()
  except rospy.ROSInterruptException:
    pass

最後一段程式碼的用意在於,倘若今天該檔案是自己被執行時(例 ./talker.py),則執行takler()這個函式;若該檔案是被當成一個 class ,import 到其他檔案中時,則不執行任何動作。

結語

建置 Publisher 的程式並不複雜,其實只要釐清 Node 需要向 Topic 發布什麼 Message 以及 Message 的格式,剩餘的其實就只要根據需求添加其他功能而已。例如本次程式碼中的 rospy.loginfo(hello_str) 其實也沒什麼多大的用意。最主要的還是要知道 pub.publish(hello_str) 當中,hello_str 即為 Subscriber 所需的 Message 即可!明天我們則會開始介紹如何同樣透過 Python 建置一個 Subscriber,以及這個 Subscriber 在接收到 Message 後應該做什麼事,請各位敬請期待。
https://ithelp.ithome.com.tw/upload/images/20200926/20129807zRH917kCyg.png


上一篇
[DAY 10]ROS Messages 的介紹與應用
下一篇
[DAY 12] Publisher && subscriber 的應用 2
系列文
ROS系統控制自走車搭配點雲雷達(隧道檢測裝置)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言